#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/select.h>
#include <cstring>
#include "Sock.hpp"
#include "Log.hpp"
using namespace std;
const static int gport = 8888;
const static int defaultevent = 0;
#define READ_EVENT (0x01)
#define WRITE_EVENT (0x01 << 1)
#define EXCEPT_EVENT (0x01)

typedef struct FdEvent
{
    int fd;
    uint8_t event;
    string clientip;
    uint16_t clientport;
} type_t;

// static const int defaultfd = -1;
class SelectServer
{
    static const int N = sizeof(fd_set) * 8;

public:
    SelectServer(uint16_t port = gport) : port_(port) {}

    void Init()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        for (int i = 0; i < N; i++)
        {
            fdarray_[i].fd = defaultfd;
            fdarray_[i].event = defaultevent;
            fdarray_[i].clientport = 0;
        }
    }
    void Accepter()
    {
        // cout<<"有一个新连接到来"<<endl;
        // listen套接字就绪后accept
        // accpet不会阻塞 原因：已近判断了listen套接字读事件就绪了 说明一定有连接 可以accpet
        string clientip;
        uint16_t clientport;
        int sock = listensock_.Accept(&clientip, &clientport);
        if (sock < 0)
            return;
        // 得到对应的sock后 sock上数据是否就绪(不能直接recv/read 否则就是阻塞式的了)
        // 将sock交给select  将新的套接字交给select管理
        logMessage(Debug, "[%s:%d],sock:%d", clientip.c_str(), clientport, sock);
        // 将sock添加到第三方数组
        int i = 1;
        for (; i < N; i++)
        {
            if (fdarray_[i].fd == defaultfd)
                break;
        }
        if (i >= N)
        {
            close(sock);
            logMessage(Warning, "sockfd array full");
        }
        else
        {
            fdarray_[i].fd = sock;
            fdarray_[i].event=READ_EVENT;
        }
    }
    void Recver(int index)
    {
        // ServiceIO();
        int fd = fdarray_[index].fd;
        char buffer[1024];
        ssize_t s = recv(fd, buffer, sizeof(buffer) - 1, 0); // recv读取一次不会阻塞，（当前已经有事件就绪了）
        if (s > 0)
        {
            buffer[s - 1] = 0;
            cout << "client# " << buffer << endl;

            // echo server
            string echo = buffer;
            echo += "[select server echo]";
            send(fd, echo.c_str(), echo.size(), 0);
        }
        else
        {
            if (s == 0)
                logMessage(Info, "client quit,fdarrray_[i]->defaultfd:%d->%d", fd, defaultfd);
            else
                logMessage(Warning, "recv error,fdarrray_[i]->defaultfd:%d->%d", fd, defaultfd);

            close(fdarray_[index].fd);
            fdarray_[index].fd = defaultfd;
            fdarray_[index].event=defaultevent;
            fdarray_[index].clientip.resize(0);
            fdarray_[index].clientport=0;
        }
    }
    void HandlerEvent(fd_set &rfds, fd_set &wfds)
    {
        for (int i = 0; i < N; i++)
        {
            if (fdarray_[i].fd == defaultfd)
                continue;
            if ((fdarray_[i].event & READ_EVENT) && (FD_ISSET(fdarray_[i].fd, &rfds)))
            {
                // 读取处理1.accept 2.read
                if ((fdarray_[i].fd == listensock_.Fd()) && (FD_ISSET(listensock_.Fd(), &rfds))) // 是listen套接字并且就绪
                {
                    Accepter();
                }
                else if ((fdarray_[i].fd != listensock_.Fd()) && (FD_ISSET(fdarray_[i].fd, &rfds))) // 读事件
                {
                    Recver(i);
                }
            }
            else if((fdarray_[i].event & WRITE_EVENT) && (FD_ISSET(fdarray_[i].fd, &wfds)))
            {
                //写事件
            }
        }
    }
    void Start()
    {
        // 启动时将listensock添加到第三方数组
        fdarray_[0].fd = listensock_.Fd();
        fdarray_[0].event = READ_EVENT;

        while (true)
        {
            // struct timeval timeout = {2, 0};
            // int n = select(listensock_.Fd() + 1, &rfds, nullptr, nullptr, timeout);//非阻塞式等待
            // 对rfds进行重置  所有fd保存在第三方数组中
            // 服务器运行中，sockfd一直在动态变化，maxfd最大文件描述符值也动态变化
            // 在网络当中 新连接到来被当作读事件就绪
            fd_set rfds;
            fd_set wfds;
            fd_set fds;

            FD_ZERO(&rfds); // fd_set清空
            FD_ZERO(&wfds); // fd_set清空

            // FD_SET(listensock_.Fd(), &rfds);                                        // fd_set添加
            // 通过第三方数组添加fd_Set
            int maxfd = fdarray_[0].fd;
            for (int i = 0; i < N; i++)
            {
                if (fdarray_[i].fd == defaultfd)
                    continue;
                //// fd_set添加
                if (fdarray_[i].event & READ_EVENT)
                    FD_SET(fdarray_[i].fd, &rfds);
                if (fdarray_[i].event & WRITE_EVENT)
                    FD_SET(fdarray_[i].fd, &wfds);

                if (maxfd < fdarray_[i].fd)
                    maxfd = fdarray_[i].fd; // 更新最大描述符值
            }
            int n = select(maxfd + 1, &rfds, &wfds, nullptr, nullptr); // 阻塞式等待
            switch (n)
            {
            case 0:
                logMessage(Debug, "timeout, %d: %s", errno, strerror(errno));
                break;
            case -1:
                logMessage(Warning, "%d: %s", errno, strerror(errno));
                break;

            default:
                logMessage(Debug, "有一个就绪事件发生了: %d", n);
                HandlerEvent(rfds, wfds);
                DebugPrint();
                break;
            }
            sleep(1);
        }
    }
    void DebugPrint()
    {
        cout << "fdarray[]:";
        for (int i = 0; i < N; i++)
        {
            if (fdarray_[i].fd == defaultfd)
                continue;
            cout << fdarray_[i].fd << " ";
        }
        cout << "\n";
    }
    ~SelectServer()
    {
        listensock_.Close();
    }

private:
    uint16_t port_;
    Sock listensock_;
    type_t fdarray_[N]; // 第三方数组维护已经获取到的sock
};